import logging, mailbox, sys, time
from copy import copy
from datetime import datetime
from optparse import Option, OptionParser, OptionValueError, make_option

import globals
from log import init_logging
from mailmigration.dup_time import setcurtime, genstrtotime
from mailmigration.mm_time import utc, Local

def check_datetime(option, opt, value):
    try:
        return datetime.fromtimestamp(genstrtotime(value), Local)
    except (ValueError, TypeError):
        msg = """The %s option takes a time string, which can be given in any of several formats:
    1.  the string "now" (refers to the current time)
    2. a sequences of digits, like "123456890" (indicating the time in seconds after the epoch)
    3. A string like "2002-01-25T07:00:00+02:00" in datetime format
    4. An interval, which is a number followed by one of the characters s, m, h, D, W, M, or Y (indicating seconds, minutes, hourse, days, weeks, months, or years respectively), or a series of such pairs. In this case the string refers to the time that preceded the current time by the length of the interval. For instance, "1h78m" indicates the time that was one hour and 78 minutes ago. The calendar here is unsophisticated: a month is always 30 days, a year is always 365 days, and a day is always 86400 seconds.
    5. A date format of the form YYYY/MM/DD, YYYY-MM-DD, MM/DD/YYYY, or MM/DD/YYYY, which indicates midnight on the day in question, relative to the current timezone settings. For instance, "2002/3/5", "03-05-2002", and "2002-3-05" all mean March 5th, 2002.""" % opt
        raise OptionValueError(msg)

class MailMigrationOption(Option):
    TYPES = Option.TYPES + ('datetime',)
    TYPE_CHECKER = copy(Option.TYPE_CHECKER)
    TYPE_CHECKER['datetime'] = check_datetime

ARGS = {
    'migrate_mail': [
        'source_mailbox',
        'destination_mailbox',
    ],
    'dump_mailman': [
        'archive_url',
        'destination_mailbox',
    ],
}

OPTS = {
    'global': [
        MailMigrationOption('--begindate', metavar='DATE', type='datetime',
                    dest='begindate', default=None,
                    help='Date to begin retrieving messages [default: oldest]'),
        MailMigrationOption('--enddate', metavar='DATE', type='datetime',
                    dest='enddate', default=None,
                    help='Date to finish retrieving messages [default: now]'),
        make_option('-b', '--blocksize',
                    dest='blocksize', default=globals.BLOCK_SIZE, type='int', metavar='SIZE',
                    help='number of messages between mailbox flushes [default: %d]' % globals.BLOCK_SIZE),
        make_option('--create', dest='create', default=False,
                    action='store_true',
                    help='create destination mailbox [default: False]'),
        make_option('--destformat', type='choice', choices=globals.MAILBOX_FORMATS.keys(),
                    dest='destformat', default=globals.DEFAULT_DEST_FORMAT, metavar='FORMAT',
                    help='format of destination mailbox [default: %s]' % globals.DEFAULT_DEST_FORMAT),
        make_option('--dry', dest='dry', default=False,
                    action='store_true',
                    help='dry run (no actions taken on either mailbox) [default: False]'),
        make_option('-v', '--verbosity', metavar='LEVEL',
                    dest='verbosity', default=20, type='int',
                    help='level of verbosity [default: %d %s]' % (globals.VERBOSITY, globals.LOG_LEVELS)),
        make_option('-l', '--logfile',
                    dest='logfile', default=None,
                    help='file to log progress, errors to [default: console-only]'),
        make_option('--logformat',
                    dest='format', default=globals.LOG_FORMAT,
                    help='format of logged messages [default: "%s"]' % globals.LOG_FORMAT),
        make_option('--logtimestamp',
                    dest='datefmt', default=None, metavar='FORMAT',
                    help='date format for log message timestamps'),
        make_option('-c', '--colon',
                    dest='colon', default=mailbox.Maildir.colon, metavar='SEP',
                    help='character to use as maildir filename seperator [default: "%s"]' % mailbox.Maildir.colon),

    ],
    'migrate_mail': [
        #Add short + long options
        #Add long-only options
        make_option('--delete-source', dest='delete', default=False,
                    action='store_true',
                    help='delete messages from source mailbox after copying [default: False]'),
        make_option('--srcformat', type='choice', choices=globals.MAILBOX_FORMATS.keys(),
                    dest='srcformat', default=globals.DEFAULT_SRC_FORMAT, metavar='FORMAT',
                    help='format of source mailbox [default: %s]' % globals.DEFAULT_SRC_FORMAT),
    ],
    'dump_mailman': [
    ],
}

def parse_cmdline(ver, now=datetime.now(utc)):
    cmd_parser = OptionParser(usage='usage: %prog [options] ' +
                                    ' '.join(ARGS.get(globals.SCRIPT_NAME, '')),
                              version='%%prog %s' % ver,
                              option_list=OPTS['global'] + OPTS.get(globals.SCRIPT_NAME, []),
                              option_class=MailMigrationOption)

    options, args = cmd_parser.parse_args()
    options.started = now
    options.criteria = {}
    if globals.SCRIPT_NAME == 'dump_mailman':
        options.srcformat = 'mailman'
    if options.dry:
        options.criteria['dry'] = True
    if options.begindate is None:
        options.begindate = datetime.min
    else:
        options.criteria['begindate'] = options.begindate
    if options.enddate is None:
        options.enddate = datetime.max
    else:
        options.criteria['enddate'] = options.enddate

    setcurtime(int(time.mktime(now.timetuple())))
    options.logger = init_logging(options)
    #Swap text format names for class names
    if options.srcformat.lower() in globals.MAILBOX_FORMATS and options.destformat.lower() in globals.MAILBOX_FORMATS:
        #Set factory first, before text names are gone
        if (options.srcformat.lower(), options.destformat.lower()) in globals.MESSAGE_FACTORIES:
            options.msgfactory = globals.MESSAGE_FACTORIES[(options.srcformat.lower(), options.destformat.lower())]
        else:
            options.msgfactory = None
        options.srcformat = globals.MAILBOX_FORMATS[options.srcformat.lower()]
        options.destformat = globals.MAILBOX_FORMATS[options.destformat.lower()]
    else:
        options.logger.critical("Mailbox formats aren't supported. Only '%s' are.",
                      ', '.join(globals.MAILBOX_FORMATS.keys()))
        sys.exit(2)

    if len(args) == 0:
        cmd_parser.print_help()
        sys.exit(2)
    else:
        return options, args

